home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MEMORY.SWG / 0047_XMS Memory routines.pas < prev    next >
Pascal/Delphi Source File  |  1994-01-27  |  26KB  |  504 lines

  1. UNIT XMS;               {  XMS Routines, Last Updated Dec 11/93        }
  2.                         {  Copyright (C) 1993, Greg Estabrooks         }
  3.                         {  NOTE: Requires TP 6.0+ To compile.          }
  4. INTERFACE
  5. {**********************************************************************}
  6. TYPE
  7.     _32Bit = LONGINT;
  8.     XMSMovStruct = RECORD
  9.                     Amount      :_32Bit;  { 32 bit number of bytes to move}
  10.                     SourceHandle:WORD;    { Handle of Source Block.     }
  11.                     SourceOffset:_32Bit;  { 32 bit offset to source.    }
  12.                     DestHandle  :WORD;    { Handle of destination.      }
  13.                     DestOffset  :_32Bit;  { 32 bit offset to destination}
  14.                    END;
  15.                                 { If SourceHandle is 0 then SourceOffset}
  16.                                 { Is Interpereted as a SEGMENT:OFFSET   }
  17.                                 { into conventional memory.             }
  18.                                 { The Same applies to DestHandle.       }
  19. { Potential XMS Error Codes:                                            }
  20. {   BL=80h if the function is not implemented                           }
  21. {      81h if a VDISK device is detected                                }
  22. {      82h if an A20 error occurs                                       }
  23. {      8Eh if a general driver error occurs                             }
  24. {      8Fh if an unrecoverable driver error occurs                      }
  25. {      90h if the HMA does not exist                                    }
  26. {      91h if the HMA is already in use                                 }
  27. {      92h if DX is less than the /HMAMIN= parameter                    }
  28. {      93h if the HMA is not allocated                                  }
  29. {      94h if the A20 line is still enabled                             }
  30. {      A0h if all extended memory is allocated                          }
  31. {      A1h if all available extended memory handles are in use          }
  32. {      A2h if the handle is invalid                                     }
  33. {      A3h if the SourceHandle is invalid                               }
  34. {      A4h if the SourceOffset is invalid                               }
  35. {      A5h if the DestHandle is invalid                                 }
  36. {      A6h if the DestOffset is invalid                                 }
  37. {      A7h if the Length is invalid                                     }
  38. {      A8h if the move has an invalid overlap                           }
  39. {      A9h if a parity error occurs                                     }
  40. {      AAh if the block is not locked                                   }
  41. {      ABh if the block is locked                                       }
  42. {      ACh if the block's lock count overflows                          }
  43. {      ADh if the lock fails                                            }
  44. {      B0h if a smaller UMB is available                                }
  45. {      B1h if no UMBs are available                                     }
  46. {      B2h if the UMB segment number is invalid                         }
  47.  
  48. VAR
  49.         XMSControl :POINTER;    { Holds the address of the XMS API.     }
  50.         XMSError   :BYTE;       { Holds any XMS error codes.            }
  51.  
  52. FUNCTION XMSDriver :BOOLEAN;
  53.                 {  Routine to determine if an XMS driver is installed.  }
  54.                 {  If it is installed it loads XMSControl with the      }
  55.                 {  location of the XMS API for the other routines.      }
  56.  
  57. FUNCTION XMSControlAdr :POINTER;
  58.                 {  This Routine returns a pointer to the XMS Controller.}
  59.  
  60. FUNCTION XMSVer :WORD;
  61.                 {  This routine returns the version of the XMS driver   }
  62.                 {  that is currently installed.                         }
  63.  
  64. FUNCTION XMSRev :WORD;
  65.                 { Returns XMS Revision Number. Usually used with XMSVer.}
  66.  
  67. FUNCTION XMSGetFreeMem :WORD;
  68.                    {  Routine to Determine how much total XMS memory is }
  69.                    {  free.                                             }
  70.  
  71. FUNCTION XMSGetLargeBlock :WORD;
  72.                    {  Routine to Determine the size of the largest free }
  73.                    {  XMS is block.                                     }
  74.  
  75. FUNCTION XMSGetMem( Blocks:WORD ) :WORD;
  76.                     {  Routine to allocate XMS for program use.         }
  77.                     {  Blocks = k's being requested, XMSErr = ErrorCode.}
  78.                     {  Returns 16 bit handle to mem allocated.          }
  79.  
  80. PROCEDURE XMSFreeMem( Handle:WORD );
  81.                     {  Routine to free previously allocated XMS Memory. }
  82. PROCEDURE XMSMoveblock( VAR Movstruct :XMSMovStruct );
  83.                     {  Routine to move memory blocks around in XMS memory.}
  84.  
  85. PROCEDURE XMSLockBlock( Handle :WORD );
  86.                         { Routine to lock and XMS block. Locked blocks  }
  87.                         { are guarnteed not to move.                    }
  88.                         { Locked Blocks should be unlocked as soon as   }
  89.                         { possible.                                     }
  90.  
  91. PROCEDURE XMSUnLockBlock( Handle :WORD );
  92.                         { Routine to unlock a previously lock XMS block.}
  93.  
  94. PROCEDURE XMSReallocate( Handle ,NewSize :WORD );
  95.                         { Routine to reallocate and XMS Block so that it}
  96.                         { becomes equal to NewSize.                     }
  97.  
  98. FUNCTION HMAExists :BOOLEAN;
  99.                 {  This routine returns Whether or not HMA Exists.      }
  100.  
  101. PROCEDURE HMARequest( RequestType :WORD );
  102.                    { Attempt to reserve the 64k HMA area for the caller.}
  103.                    { NOTE: RequestType must be either FFFF = Application}
  104.                    { OR If caller is a TSR the RequestType = Amount of  }
  105.                    { Space wanted.                                      }
  106.  
  107. PROCEDURE HMARelease;
  108.                       { Routine to release previously allocated HMA.    }
  109.                       { NOTE: Any Code/Data store in that HMA Memory    }
  110.                       { Will become invalid and inaccessible.           }
  111.  
  112. PROCEDURE GlobaleEnableA20;
  113.                      { Routine to Enable the A20 Line. Should only be   }
  114.                      { used by programs that have control of the HMA.   }
  115.                      { NOTE: Remeber to disable the Line before         }
  116.                      {       releaseing control of the system.          }
  117.  
  118. PROCEDURE GlobaleDisableA20;
  119.                       { Routine to Disable the A20 Line. On some systems}
  120.                       { the Toggling of the A20 Line can take a long    }
  121.                       { time.                                           }
  122.  
  123. PROCEDURE LocalEnableA20;
  124.                      { Routine to Enable the A20 Line for current Program}
  125.                      { NOTE: Rember to so a LocalDisableA20 before      }
  126.                      {       releasing system control.                  }
  127.  
  128. PROCEDURE LocalDisableA20;
  129.                       { Routine to Locally Disable the A20 Line.        }
  130.  
  131. FUNCTION QueryA20 :BOOLEAN;
  132.                      { Routine to test whether the A20 is Physically    }
  133.                      { enabled or not.                                  }
  134.  
  135. FUNCTION PtrToLong( P:POINTER ) :LONGINT;
  136.                      { Routine to convert a pointer to a 32 bit number. }
  137.  
  138. IMPLEMENTATION
  139. {**********************************************************************}
  140.  
  141. FUNCTION XMSDriver :BOOLEAN; ASSEMBLER;
  142.                 {  Routine to determine if an XMS driver is installed.  }
  143.                 {  If it is installed it loads XMSControl with the      }
  144.                 {  location of the XMS API for the other routines.      }
  145. ASM
  146.   Mov AX,$4300                  {  Function to check for Driver.        }
  147.   Int $2F                       {  Call Dos Int 2Fh.                    }
  148.   Cmp AL,$80                    {  Check Result, if its 80h driver.     }
  149.   Je @Installed                 {  If It is return TRUE.                }
  150.   Mov AL,0                      {  Else Return FALSE.                   }
  151.   Jmp @Exit
  152. @Installed:
  153.   Mov AX,$4310                  {  Function to return pointer to Driver.}
  154.   Int $2F                       {  Call Interrupt.                      }
  155.   Mov XMSControl.WORD,BX        {  Pointer info returned in ES:BX.      }
  156.   Mov XMSControl+2.WORD,ES
  157.   Mov AL,1                      {  Set True Flag.                       }
  158. @Exit:
  159. END;{XMSDriver}
  160.  
  161. FUNCTION XMSControlAdr :POINTER; ASSEMBLER;
  162.                 {  This Routine returns a pointer to the XMS Controller.}
  163. ASM
  164.   Push ES                       {  Push ES onto the stack.              }
  165.   Push BX                       {  Push BX onto the stack.              }
  166.   Mov AX,$4310                  {  Function to return pointer to Driver.}
  167.   Int $2F                       {  Call Interrupt.                      }
  168.   Mov DX,ES                     {  Pointer info returned in ES:BX so    }
  169.   Mov AX,BX                     {  move it into DX:AX.                  }
  170.   Pop BX                        {  Pop BX Off the Stack.                }
  171.   Pop ES                        {  Pop ES Off the Stack.                }
  172. END;{XMSControlAdr}
  173.  
  174. FUNCTION XMSVer :WORD; ASSEMBLER;
  175.                 {  This routine returns the version of the xms driver   }
  176.                 {  that is currently installed.Version is returned as a }
  177.                 {  16 bit BCD number.                                   }
  178. ASM
  179.   Mov AH,0                      {  Function to return XMS version.      }
  180.   Call [XMSControl]             {  Call XMS Api.                        }
  181.                    {  Possible returns are :                            }
  182.                    {  AX = XMS version , BX = driver revision number    }
  183.                    {  DX = 1 if HMA exists, 0 if not.                   }
  184. END;{XMSVer}
  185.  
  186. FUNCTION XMSRev :WORD; ASSEMBLER;
  187.                 { Returns XMS Revision Number. Usually used with XMSVer.}
  188. ASM
  189.   Push BX                       {  Save BX.                             }
  190.   Mov AH,0                      {  Function to return XMS revision.     }
  191.   Call [XMSControl]             {  Call XMS Api.                        }
  192.   Mov AX,BX                     {  Move result into proper register.    }
  193.   Pop BX                        {  Restore BX.                          }
  194. END;{XMSRev}
  195.  
  196. FUNCTION XMSGetFreeMem :WORD; ASSEMBLER;
  197.                    {  Routine to Determine how much total XMS memory is }
  198.                    {  free.                                             }
  199. ASM
  200.   Push DX                       {  Save DX and BX.                      }
  201.   Push BX
  202.   Mov XMSError,0                {  Clear error flag.                    }
  203.   Mov AH,$08                    {  Function to get free XMS mem         }
  204.   Call [XMSControl]             {  Call XMS Api                         }
  205.   Mov XMSError,BL               {  Return any error code to user.       }
  206.   Mov AX,DX                     {  Load AX with Total Free k'S          }
  207.   Pop BX                        {  Restore BX and DX.                   }
  208.   Pop DX
  209.                    {  DX = Total Free in k's                            }
  210.                    {  AX = Largest free block in k's                    }
  211.                    {  BL = Err Code.                                    }
  212. END;{XMSGetFreeMem}
  213.  
  214. FUNCTION XMSGetLargeBlock :WORD; ASSEMBLER;
  215.                    {  Routine to Determine the size of the largest free }
  216.                    {  XMS is block.                                     }
  217. ASM
  218.   Push BX                       {  Save BX.                             }
  219.   Mov XMSError,0                {  Clear error flag.                    }
  220.   Mov AH,$08                    {  Function to get free XMS mem         }
  221.   Call [XMSControl]             {  Call XMS Api                         }
  222.   Mov XMSError,BL               {  Return any error code to user.       }
  223.   Pop BX                        {  Restore BX.                          }
  224.                    {  DX = Total Free in k's                            }
  225.                    {  AX = Largest free block in k's                    }
  226. END;{XMSGetLargeBlock}
  227.  
  228. FUNCTION XMSGetMem( Blocks:WORD ) :WORD; ASSEMBLER;
  229.                     {  Routine to allocate XMS for programs use         }
  230.                     {  Blocks = k's being requested, XMSErr = ErrorCode }
  231.                     {  Returns 16 bit handle to mem allocated           }
  232. ASM
  233.   Push DX                       {  Save DX and BX.                      }
  234.   Push BX
  235.   Mov XMSError,0                {  Clear error flag.                    }
  236.   Mov AH,9                      {  Function Allocate Extended Memory    }
  237.   Mov DX,Blocks                 {  Load k Blocks to be allocated        }
  238.   Call [XMSControl]             {  Call XMS API                         }
  239.   Mov XMSError,BL               {  Return any error code to user.       }
  240.   Mov AX,DX                     {  Load 16 Bit Handle to allocated Mem  }
  241.   Pop BX                        {  Restore BX and DX.                   }
  242.   Pop DX
  243.          {NOTE: If there was an Error then the handle is invalid. }
  244. END;{XMSGetMem}
  245.  
  246. PROCEDURE XMSFreeMem( Handle:WORD ); ASSEMBLER;
  247.                     {  Routine to free previously allocated XMS Memory  }
  248. ASM
  249.   Push DX                       {  Save DX and BX.                      }
  250.   Push BX
  251.   Mov XMSError,0                {  Clear error flag.                    }
  252.   Mov AH,$0A                    {  Function Free Allocated Memory       }
  253.   Mov DX,Handle                 {  Load Handle of Memory to free        }
  254.   Call [XMSControl]             {  Call API                             }
  255.   Mov XMSError,BL               {  Return any error code to user.       }
  256.   Pop BX                        {  Restore BX and DX.                   }
  257.   Pop DX
  258. END;{XMSFreeMem}
  259.  
  260. PROCEDURE XMSMoveblock( VAR Movstruct :XMSMovStruct ); ASSEMBLER;
  261.          {  Routine to move memory blocks around in XMS memory.         }
  262.          {  Length must be even.                                        }
  263. ASM
  264.   Push DS                       {  Save DS and SI                       }
  265.   Push SI
  266.   Push BX
  267.   Mov XMSError,0                {  Clear error flag.                    }
  268.   LDS SI,MovStruct              {  Point DS:SI to move Structure        }
  269.   Mov AH,$0B                    {  Function to Move Extended memory block}
  270.   Call [XMSControl]             {  Call XMS API                         }
  271.   Mov XMSError,BL               {  Save any error code for user.        }
  272.   Pop BX
  273.   Pop SI                        {  Restore DS and SI                    }
  274.   Pop DS
  275. END;{XMSMoveBlock}
  276.  
  277. PROCEDURE XMSLockBlock( Handle :WORD ); ASSEMBLER;
  278.                         { Routine to lock and XMS block. Locked blocks  }
  279.                         { are guarnteed not to move.                    }
  280.                         { Locked Blocks should be unlocked as soon as   }
  281.                         { possible.                                     }
  282. ASM
  283.   Push DX                       {  Save DX and BX.                      }
  284.   Push BX
  285.   Mov XMSError,0                {  Clear Error Flag.                    }
  286.   Mov AH,$0C                    {  Function to lock XMS Block.          }
  287.   Mov DX,Handle                 {  Handle of block to lock.             }
  288.   Call [XMSControl]             {  Call XMS Api.                        }
  289.   Mov XMSError,BL               {  Save any error codes.                }
  290.   Pop BX                        {  Restore BX and DX.                   }
  291.   Pop DX
  292. END;{XMSLockBlock}
  293.  
  294. PROCEDURE XMSUnLockBlock( Handle :WORD ); ASSEMBLER;
  295.                         { Routine to unlock a previously lock XMS block.}
  296. ASM
  297.   Push DX                       {  Save DX and BX.                      }
  298.   Push BX
  299.   Mov XMSError,0                {  Clear Error Flag.                    }
  300.   Mov AH,$0D                    {  Function to unlock XMS Block.        }
  301.   Mov DX,Handle                 {  Handle of block to unlock.           }
  302.   Call [XMSControl]             {  Call XMS Api.                        }
  303.   Mov XMSError,BL               {  Save any error codes.                }
  304.   Pop BX                        {  Restore BX and DX.                   }
  305.   Pop DX
  306. END;{XMSUnLockBlock}
  307.  
  308. PROCEDURE XMSReallocate( Handle ,NewSize :WORD ); ASSEMBLER;
  309.                         { Routine to reallocate and XMS Block so that it}
  310.                         { becomes equal to NewSize.                     }
  311. ASM
  312.   Push DX                       {  Save DX and BX.                      }
  313.   Push BX
  314.   Mov XMSError,0                {  Clear Error Flag.                    }
  315.   Mov BX,NewSize                {  Load New size of XMS Block.          }
  316.   Mov DX,Handle                 {  Handle of an unlocked XMS Block.     }
  317.   Mov AH,$0F                    {  Function to Reallocate XMS Block.    }
  318.   Mov DX,Handle                 {  Handle of block to lock.             }
  319.   Call [XMSControl]             {  Call XMS Api.                        }
  320.   Mov XMSError,BL               {  Save any error codes.                }
  321.   Pop BX                        {  Restore BX and DX.                   }
  322.   Pop DX
  323. END;{XMSReallocate}
  324.  
  325. FUNCTION HMAExists :BOOLEAN; ASSEMBLER;
  326.                 {  This routine returns Whether or not HMA Exists       }
  327. ASM
  328.   Push DX                       {  Save DX.                             }
  329.   Mov AH,0                      {  Function to return HMA Status        }
  330.   Call [XMSControl]             {  Call XMS Api                         }
  331.   Mov AL,DL                     {  Mov Status into proper register      }
  332.   Pop DX                        {  Restore DX.                          }
  333.                    {  Possible returns are :                            }
  334.                    {  AX = XMS version , BX = driver revision number    }
  335.                    {  DX = 1 if HMA exists, 0 if not                    }
  336. END;{HMAExists}
  337.  
  338. PROCEDURE HMARequest( RequestType :WORD ); ASSEMBLER;
  339.                    { Attempt to reserve the 64k HMA area for the caller.}
  340.                    { NOTE: RequestType must be either FFFF = Application}
  341.                    { OR If caller is a TSR the RequestType = Amount of  }
  342.                    { Space wanted.                                      }
  343. ASM
  344.   Push DX                       {  Save DX.                             }
  345.   Push BX
  346.   Mov AH,1                      {  Function to request HMA.             }
  347.   Mov XMSError,0                {  Clear error flag.                    }
  348.   Mov DX,RequestType            {  Load whether area is for an App or TSR.}
  349.   Call [XMSControl]             {  Call XMS API                         }
  350.   Mov XMSError,BL               {  Return any error code to user.       }
  351.   Pop Bx
  352.   Pop DX                        {  Restore DX.                          }
  353. END;{HMARequest}
  354.  
  355. PROCEDURE HMARelease; ASSEMBLER;
  356.                       { Routine to release previously allocated HMA.    }
  357.                       { NOTE: Any Code/Data store in that HMA Memory    }
  358.                       { Will become invalid and inaccessible.           }
  359. ASM
  360.   Push DX                       {  Save DX.                             }
  361.   Mov AH,2                      {  Function to release HMA.             }
  362.   Mov XMSError,0                {  Clear error flag.                    }
  363.   Call [XMSControl]             {  Call XMS API                         }
  364.   Mov XMSError,BL               {  Return any error code to user.       }
  365.   Pop DX                        {  Restore DX.                          }
  366. END;{HMARelease}
  367.  
  368. PROCEDURE GlobaleEnableA20; ASSEMBLER;
  369.                      { Routine to Enable the A20 Line. Should only be   }
  370.                      { used by programs that have control of the HMA.   }
  371.                      { NOTE: Remeber to disable the Line before         }
  372.                      {       releaseing control of the system.          }
  373. ASM
  374.   Push BX                       { Push BX onto the Stack.               }
  375.   Mov XMSError,0                { Clear Error flag.                     }
  376.   Mov AH,3                      { Function to Enable A20 line.          }
  377.   Call [XMSControl]             { Call XMS Api.                         }
  378.   Mov XMSError,BL               { Save any errors.                      }
  379.   Pop BX                        { Pop BX Off the Stack.                 }
  380. END;{GlobalEnableA20}
  381.  
  382. PROCEDURE GlobaleDisableA20; ASSEMBLER;
  383.                       { Routine to Disable the A20 Line. On some systems}
  384.                       { the Toggling of the A20 Line can take a long    }
  385.                       { time.                                           }
  386. ASM
  387.   Push BX                       { Push BX onto the Stack.               }
  388.   Mov XMSError,0                { Clear Error flag.                     }
  389.   Mov AH,4                      { Function to Disable A20 line.         }
  390.   Call [XMSControl]             { Call XMS Api.                         }
  391.   Mov XMSError,BL               { Save any errors.                      }
  392.   Pop BX                        { Pop BX Off the Stack.                 }
  393. END;{GlobalDisableA20}
  394.  
  395. PROCEDURE LocalEnableA20; ASSEMBLER;
  396.                      { Routine to Enable the A20 Line for current Program}
  397.                      { NOTE: Rember to so a LocalDisableA20 before      }
  398.                      {       releasing system control.                  }
  399. ASM
  400.   Push BX                       { Push BX onto the Stack.               }
  401.   Mov XMSError,0                { Clear Error flag.                     }
  402.   Mov AH,5                      { Function to Enable A20 line.          }
  403.   Call [XMSControl]             { Call XMS Api.                         }
  404.   Mov XMSError,BL               { Save any errors.                      }
  405.   Pop BX                        { Pop BX Off the Stack.                 }
  406. END;{LocalEnableA20}
  407.  
  408. PROCEDURE LocalDisableA20; ASSEMBLER;
  409.                       { Routine to Locally Disable the A20 Line.        }
  410. ASM
  411.   Push BX                       { Push BX onto the Stack.               }
  412.   Mov XMSError,0                { Clear Error flag.                     }
  413.   Mov AH,6                      { Function to Disable A20 line.         }
  414.   Call [XMSControl]             { Call XMS Api.                         }
  415.   Mov XMSError,BL               { Save any errors.                      }
  416.   Pop BX                        { Pop BX Off the Stack.                 }
  417. END;{LocalDisableA20}
  418.  
  419. FUNCTION QueryA20 :BOOLEAN; ASSEMBLER;
  420.                      { Routine to test whether the A20 is Physically    }
  421.                      { enabled or not.                                  }
  422. ASM
  423.   Push BX                       { Push BX onto the Stack.               }
  424.   Mov XMSError,0                { Clear Error flag.                     }
  425.   Mov AH,7                      { Function to test the A20 line.        }
  426.   Call [XMSControl]             { Call XMS Api.                         }
  427.   Mov XMSError,BL               { Save any errors.                      }
  428.   Pop BX                        { Pop BX Off the Stack.                 }
  429. END;{QueryA20}
  430.  
  431. FUNCTION PtrToLong( P:POINTER ) :LONGINT; ASSEMBLER;
  432.                      { Routine to convert a pointer to a 32 bit number. }
  433. ASM
  434.   Mov AX,P.WORD[0]                 { Load low WORD into AX.             }
  435.   Mov DX,P.WORD[2]                 { Load high WORD into DX.            }
  436. END;{PtrToLong}
  437.  
  438. BEGIN
  439. END.
  440.  
  441. {---------------------------- CUT HERE FOR DEMO -------------------}
  442. {***********************************************************************}
  443. PROGRAM XMSDemo1;            { Demonstration of the XMS Unit.           }
  444.                              { Last Updated Dec 10/93, Greg Estabrooks. }
  445. USES CRT,                    { IMPORT Clrscr,Writeln.                   }
  446.      XMS;                    { IMPORT XMSDriver,XMSVer,XMSGetFreeMem,   }
  447.                              { XMSGetLargeBlock,XMSGetMem,XMSMove,      }
  448.                              { XMSError,XMSMovStruct,XMSFreeMem.        }
  449. VAR
  450.    XMSHandle  :WORD;            { Holds the handle of our XMS Area.     }
  451.    MovInf     :XMSMovStruct;    { Move Structure for Moving XMS Blocks. }
  452. BEGIN
  453.   Clrscr;                       { Clear away any screen clutter.        }
  454.   IF XMSDriver THEN             { If XMS Driver installed do demo.      }
  455.   BEGIN
  456.     Write('XMS Driver Version ');   { Show Version Installed.           }
  457.     Writeln(HI(XMSVer),'.',LO(XMSVer),'.',XMSRev,' Installed');
  458.     Writeln('Total Free XMS Memory : ',XMSGetFreeMem,'k');
  459.     Writeln('Largest Free XMS Block: ',XMSGetLargeBlock,'k');
  460.     Writeln;
  461.  
  462.     Writeln('Attempting to Allocate 16k of XMS');
  463.     XMSHandle := XMSGetMem(16); { Attempt to allocate 16k of XMS.       }
  464.     Writeln('ErrorCode Returned : ',XMSError);
  465.     Writeln('Current free XMS Memory : ',XMSGetFreeMem);
  466.     Writeln;
  467.  
  468.     Writeln('Saving Screen to XMS.');
  469.     WITH MovInf DO
  470.       BEGIN
  471.         Amount := 4000;         { Length of the Video Screen.           }
  472.         SourceHandle := 0;      { If SourceHandle is 0 then SourceOffset}
  473.                                 { Is Interpereted as a SEGMENT:OFFSET   }
  474.                                 { into conventional memory.             }
  475.         SourceOffset := PtrToLong(Ptr($B800,0));
  476.         DestHandle := XMSHandle;{ Destination is our XMS block.         }
  477.         DestOffset := 0;
  478.       END;
  479.     XMSMoveBlock(MovInf);
  480.     Writeln('Press <ENTER> to continue.');
  481.     Readln;
  482.  
  483.     Clrscr;
  484.     Writeln('Press <ENTER> to Restore Screen.');
  485.     Readln;
  486.  
  487.     WITH MovInf DO
  488.       BEGIN
  489.         Amount := 4000;         { Length of the Video Screen.           }
  490.         SourceHandle := XMSHandle;
  491.         SourceOffset := 0;
  492.         DestHandle := 0;
  493.         DestOffset := PtrToLong(Ptr($B800,0));;
  494.       END;
  495.     XMSMoveBlock(MovInf);
  496.     GotoXY(1,11);
  497.     XMSFreeMem(XMSHandle);      { Free allocate XMS.                    }
  498.     Writeln('Ending Free XMS Memory : ',XMSGetFreeMem,'k');
  499.   END
  500.   ELSE
  501.     Writeln('XMS Driver not Installed!',^G);
  502.   Readln;
  503. END.{XMSDemo1}
  504. {***********************************************************************}